package com.ruoyi.douyin.service.imp;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.common.constant.ConstantDouYinBase;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.vo.AuthVo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.AjaxUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.douyin.service.AuthService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.DouyinUser;
import com.ruoyi.system.service.DouyinUserService;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class AuthServiceImp implements AuthService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AjaxUtils ajaxUtils;
    // 令牌自定义标识
    @Value("${token.header}")
    private String header;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private DouyinUserService douyinUserService;

    /**
     * 抖音授权
     */
    @Override
    public String douyinAuth() {
        String token = ServletUtils.getRequest().getHeader(this.header);
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        String path = ConstantDouYinBase.Url.BASE_URL.getUrl() + ConstantDouYinBase.Url.AUTH_URL_CODE.getUrl();
        path += "?client_key=" + ConstantDouYinBase.App.BASE.getClientKey() +
                "&response_type=code&scope="
                + "user_info,video.data,video.list,mobile_alert,fans.list,following.list,data.external.user,data.external.item"
                + "&redirect_uri=http://zs.91gongju.cn/base/douyin/access/token&state="
                + token;
        return path;
    }

    /**
     * 通过code获取accessToken
     *
     * @param code  授权码
     * @param state Token
     */
    @Override
    public AjaxResult douyinAccessToken(String code, String state) {
        Claims claims = tokenService.parseToken(state);
        // 解析对应的权限以及用户信息
        String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
        String userKey = tokenService.getTokenKey(uuid);
        // 获取到用户信息
        LoginUser loginUser = redisCache.getCacheObject(userKey);
        String url = ConstantDouYinBase.Url.BASE_URL.getUrl() + ConstantDouYinBase.Url.AUTH_URL_ACCESS_TOKEN.getUrl();
        Map<String, Object> param = new HashMap<>();
        param.put("client_key", ConstantDouYinBase.App.BASE.getClientKey());
        param.put("client_secret", ConstantDouYinBase.App.BASE.getClientSecret());
        param.put("code", code);
        param.put("grant_type", "authorization_code");
        try {
            AjaxResult ajaxResult = ajaxUtils.doGetWithParams(url, param);
            Object data = ajaxResult.get("data");
            Type type = new TypeReference<Map<String, Object>>() {
            }.getType();
            Map<String, Object> dataResult = JSON.parseObject(data.toString(), type);
            if (!"success".equalsIgnoreCase(dataResult.get("message").toString())) return AjaxResult.error("授权失败，从新授权");
            String accessToken = ((Map<String, Object>) dataResult.get("data")).get("access_token").toString();
            String refreshToken = ((Map<String, Object>) dataResult.get("data")).get("refresh_token").toString();
            String openId = ((Map<String, Object>) dataResult.get("data")).get("open_id").toString();
            String expire = ((Map<String, Object>) dataResult.get("data")).get("expires_in").toString();
            AuthVo authVo = new AuthVo();
            authVo.setAccessToken(accessToken);
            authVo.setRefreshToken(refreshToken);
            authVo.setOpenId(openId);
            Boolean isBind = douyinUserService.isBindByOpenId(openId);
            // 使用OpenId存储用户的AccessToken
            redisCache.setCacheObject(openId, authVo, Long.parseLong(expire), TimeUnit.SECONDS);
            if (isBind) {
                DouyinUser douyinUser = (DouyinUser) this.userInfo(openId).get("data");
                douyinUser.setOpenId(openId);
                douyinUser.setUserId(loginUser.getUser().getUserId());
                douyinUserService.bindUser(douyinUser);
            }
            // 更新用户的信息
            if (loginUser.getOpenId() == null) {
                loginUser.setOpenId(Collections.singletonList(openId));
                redisCache.setCacheObject(userKey, loginUser,
                        loginUser.getExpireTime(),
                        TimeUnit.MINUTES);
            } else {
                List<String> originOpenId = loginUser.getOpenId();
                HashSet<String> openIds = new HashSet<>(originOpenId);
                if (!openIds.contains(openId)) {
                    originOpenId.add(openId);
                    loginUser.setOpenId(originOpenId);
                    redisCache.setCacheObject(userKey, loginUser,
                            loginUser.getExpireTime(),
                            TimeUnit.MINUTES);
                }
            }
            return AjaxResult.success();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error();
    }

    /**
     * 获取用户信息
     */
    @Override
    public AjaxResult userInfo(List<String> originOpenId) {
        List<DouyinUser> douyinUsers = new ArrayList<>();
        for (String openId : originOpenId) {
            AuthVo authVo = redisCache.getCacheObject(openId);
            if (authVo == null) {
                return AjaxResult.error("授权过期");
            }
            String url = ConstantDouYinBase.Url.BASE_URL.getUrl()
                    + ConstantDouYinBase.Url.USER_INFO.getUrl()
                    + "?open_id=" + openId + "&access_token=" + authVo.getAccessToken();
            String result = HttpUtil.get(url);
            Map<String, Object> objectMap = JSON.parseObject(result, new TypeReference<Map<String, Object>>() {
            }.getType());
            Map data = (Map) objectMap.get("data");
            DouyinUser douyinUser = new DouyinUser();
            douyinUser.setAvatar(data.get("avatar").toString())
                    .setCountry(data.get("country").toString())
                    .setGender(Integer.parseInt(data.get("gender").toString()))
                    .setCity(data.get("city").toString())
                    .setDescUrl(data.get("desc_url").toString())
                    .setDescription(data.get("description").toString())
                    .setEAccountRole(data.get("e_account_role").toString())
                    .setAvatarLarger(data.get("avatar_larger").toString())
                    .setClientKey(data.get("client_key").toString())
                    .setProvince(data.get("province").toString())
                    .setCaptcha(data.get("captcha").toString())
                    .setDistrict(data.get("district").toString())
                    .setNickname(data.get("nickname").toString())
                    .setOpenId(openId)
                    .setUnionId(data.get("union_id").toString());
            Object encryptMobile = data.get("encrypt_mobile");
            Optional.ofNullable(encryptMobile).ifPresent(mobile -> douyinUser.setEncryptMobile(mobile.toString()));
            douyinUser.setErrorCode(Integer.parseInt(data.get("error_code").toString()));
            douyinUsers.add(douyinUser);
        }
        return AjaxResult.success("success", douyinUsers);
    }

    public AjaxResult userInfo(String openId) {
        AuthVo authVo = redisCache.getCacheObject(openId);
        if (authVo == null) {
            return AjaxResult.error("授权过期");
        }
        String url = ConstantDouYinBase.Url.BASE_URL.getUrl()
                + ConstantDouYinBase.Url.USER_INFO.getUrl()
                + "?open_id=" + openId + "&access_token=" + authVo.getAccessToken();
        String result = HttpUtil.get(url);
        Map<String, Object> objectMap = JSON.parseObject(result, new TypeReference<Map<String, Object>>() {
        }.getType());
        Map data = (Map) objectMap.get("data");
        DouyinUser douyinUser = new DouyinUser();
        douyinUser.setAvatar(data.get("avatar").toString());
        douyinUser.setCountry(data.get("country").toString());
        douyinUser.setGender(Integer.parseInt(data.get("gender").toString()));
        douyinUser.setCity(data.get("city").toString());
        douyinUser.setDescUrl(data.get("desc_url").toString());
        douyinUser.setDescription(data.get("description").toString());
        douyinUser.setEAccountRole(data.get("e_account_role").toString());
        douyinUser.setAvatarLarger(data.get("avatar_larger").toString());
        douyinUser.setClientKey(data.get("client_key").toString());
        douyinUser.setProvince(data.get("province").toString());
        douyinUser.setCaptcha(data.get("captcha").toString());
        douyinUser.setDistrict(data.get("district").toString());
        douyinUser.setNickname(data.get("nickname").toString());
        douyinUser.setUnionId(data.get("union_id").toString());
        Object encryptMobile = data.get("encrypt_mobile");
        Optional.ofNullable(encryptMobile).ifPresent(mobile -> douyinUser.setEncryptMobile(mobile.toString()));
        douyinUser.setErrorCode(Integer.parseInt(data.get("error_code").toString()));
        return AjaxResult.success("success", douyinUser);
    }

    /**
     * 绑定抖音用户的信息列表
     */
    @Override
    public AjaxResult userInfoList() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        List<DouyinUser> douyinUserByUserId = douyinUserService.getDouyinUserByUserId(loginUser.getUser().getUserId());
        return AjaxResult.success("success", douyinUserByUserId);
    }

    @Override
    public AjaxResult userInfoListFull() {
        ArrayList<HashMap<String, Object>> resultList = new ArrayList<>();
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        List<DouyinUser> douyinUserByUserId = douyinUserService.getDouyinUserByUserId(loginUser.getUser().getUserId());
        for (DouyinUser douyinUser : douyinUserByUserId) {
            HashMap<String, Object> resultMap = new HashMap<>();
            String openId = douyinUser.getOpenId();
            try {
                AuthVo authVo = redisCache.getCacheObject(openId);
                resultMap.put("userInfo", douyinUser);
                if (authVo == null) {
                    resultMap.put("authInfo", false);
                } else {
                    resultMap.put("authInfo", true);
                }
                resultList.add(resultMap);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return AjaxResult.success("authVo", resultList);
    }
}
